package com.jbp.service;

import com.alibaba.fastjson.JSON;
import com.google.gson.reflect.TypeToken;
import com.jbp.domin.LuckReq2;
import com.jbp.exception.RRException;
import com.jbp.model.Gift;
import com.jbp.model.Pool;
import com.jbp.model.PoolRoom;
import com.jbp.redis.RedisConfigService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class LuckVUtil {
    @Autowired
    private RedisConfigService redisConfigService;
    @Autowired
    private PoolGiftConfigService poolGiftConfigService;
    @Autowired
    private GiftService giftService;
    @Autowired
    private UserDailyLuckRecordService userDailyLuckRecordService;
    @Autowired
    private AppConfigService appConfigService;

    @Autowired
    private PoolRoomService poolRoomService;

    @Autowired
    private DevicePoolService devicePoolService;
    @Autowired
    private UserService userService;

    /**
     * 新版抽奖
     * @param luckReq
     * @param pool
     * @param poolXUserId
     * @return
     */
    public List<Gift> luck(LuckReq2 luckReq, Pool pool, Integer poolXUserId) {
        String key = "kchat:pool:" + luckReq.getPrice();
        //看用户是否有指定奖池
        if (pool.getType() != 0) {
            key = key + ":poolXUserId=" + poolXUserId;
        }
        key = key + ":pool=" + pool.getId();
        //是否个池
        if (pool.getCom() != 1) {
            key = key + ":userid=" + luckReq.getUserId();
        }/* else {
            key = key + ":roomid="+luckReq.getRoomId();
        }*/
        if (luckReq.getType()==2) {
            //机器人
            key = key+":rob";
        }

        List<Gift> gifts = new ArrayList<>();

        Map<Integer, Gift> giftMap = new HashMap<>();

        //房间池  //限制盈利
        HashMap<String, BigDecimal> winMap = new HashMap<>();
//        PoolRoom poolRoom = poolRoomService.getByRoomId(luckReq.getRoomId());
        PoolRoom poolRoom = poolRoomService.getPoolRoomByUserId(luckReq.getUserId());

        int maxGift = 0;
        if (poolRoom != null && luckReq.getPrice() != 100) {
            if (poolRoom.getMaxGift() != null) {
                maxGift = poolRoom.getMaxGift();
            }
        }

        //抽奖
        for (Integer i = 0; i < luckReq.getTimes(); i++) {
            while (true){
                Map<Integer, Integer> map = getPool(key, pool);//pool_gift_config表-key:giftId,value:giftNum
                int giftId = doLuck(map);//pool_gift_config key=giftid   value = number
                updatePool(key, map);

                if (giftId == 0) {
                    throw new RRException("网络错误1003");
                }
                if (!giftMap.containsKey(giftId)) {
                    Gift gift = giftMap.get(giftId);
                    if (gift == null) {
                        gift = giftService.getById(giftId);
                        giftMap.put(giftId, gift);
                    }
                }
                Gift gift = giftMap.get(giftId);
                if (maxGift > 0){
                    if(gift.getCoin() <= maxGift) {
                        Gift out = new Gift();
                        BeanUtils.copyProperties(gift, out);
                        gifts.add(out);
                        break;
                    }
                }else {
                    Gift out = new Gift();
                    BeanUtils.copyProperties(gift, out);
                    gifts.add(out);
                    break;
                }
            }
        }


        /*for (Integer i = 0; i < luckReq.getTimes(); i++) {
            Map<Integer, Integer> map = getPool(key, pool);//pool_gift_config表-key:giftId,value:giftNum
            int giftId = doLuck(map);//pool_gift_config key=giftid   value = number
            updatePool(key, map);

            if (giftId == 0) {
                throw new RRException("网络错误1003");
            }

            if (!giftMap.containsKey(giftId)) {
                Gift gift = giftMap.get(giftId);
                if (gift == null) {
                    gift = giftService.getById(giftId);
                    giftMap.put(giftId, gift);
                }
            }

            Gift gift = giftMap.get(giftId);
            Gift out = new Gift();
            BeanUtils.copyProperties(gift, out);
            gifts.add(out);
        }*/

        //保105
        protect105(luckReq, gifts, pool.getId());

        return gifts;
    }

    /**
     * 机器人抽奖
     * @param luckReq
     * @param pool
     * @param poolXUserId
     * @return
     */
    public List<Gift> luckRob(LuckReq2 luckReq, Pool pool, Integer poolXUserId) {
        String key = "kchat:pool:" + luckReq.getPrice();
        //看用户是否有指定奖池
        if (pool.getType() != 0) {
            key = key + ":poolXUserId=" + poolXUserId;
        }
        key = key + ":pool=" + pool.getId();
        //是否个池
        if (pool.getCom() != 1) {
            key = key + ":userid=" + luckReq.getUserId();
        }/* else {
            key = key + ":roomid="+luckReq.getRoomId();
        }*/
        if (luckReq.getType()==2) {
            //机器人
            key = key+":rob";
        }

        List<Gift> gifts = new ArrayList<>();

        Map<Integer, Gift> giftMap = new HashMap<>();

        //抽奖
        for (Integer i = 0; i < luckReq.getTimes(); i++) {
            Map<Integer, Integer> map = getRobPool(key, pool);
            int giftId = doLuck(map);//pool_gift_config key=giftid   value = number
            updatePool(key, map);

            if (giftId == 0) {
                throw new RRException("网络错误1003");
            }

            if (!giftMap.containsKey(giftId)) {
                Gift gift = giftMap.get(giftId);
                if (gift == null) {
                    gift = giftService.getById(giftId);
                    giftMap.put(giftId, gift);
                }
            }

            Gift gift = giftMap.get(giftId);
            Gift out = new Gift();
            BeanUtils.copyProperties(gift, out);
            /*if (gift.getCoin()>=500 && gift.getCoin()<=6666) {
                gifts.add(out);
            }*/
            gifts.add(out);
        }

        //保105
        protect105(luckReq, gifts, pool.getId());

        return gifts;
    }

    /**
     * 设备池抽奖
     * @param luckReq
     * @param pool
     * @param poolXUserId
     * @return
     */
    public List<Gift> luckDevice(LuckReq2 luckReq, Pool pool, Integer poolXUserId) {
        String key = "kchat:pool:" + luckReq.getPrice();
        //看用户是否有指定奖池
        /*if (pool.getType() != 0) {
            key = key + ":poolXUserId=" + poolXUserId;
        }*/
        key = key + ":pool=" + pool.getId();
        //是否个池
        /*if (pool.getCom() != 1) {
            key = key + ":userid=" + luckReq.getUserId();
        } else {
            key = key + ":roomid="+luckReq.getRoomId();
        }*/
        /*if (luckReq.getType()==2) {
            //机器人
            key = key+":rob";
        }*/

        List<Gift> gifts = new ArrayList<>();

        Map<Integer, Gift> giftMap = new HashMap<>();

        //抽奖
        for (Integer i = 0; i < luckReq.getTimes(); i++) {
            Map<Integer, Integer> map = getPool(key, pool);
            int giftId = doLuck(map);
            updatePool(key, map);

            if (giftId == 0) {
//                devicePoolService.removeById(luckReq.getDeviceId());//删除拉入到设备池中的用户设备数据
                throw new RRException("网络错误1003");
            }

            if (!giftMap.containsKey(giftId)) {
                Gift gift = giftMap.get(giftId);
                if (gift == null) {
                    gift = giftService.getById(giftId);
                    giftMap.put(giftId, gift);
                }
            }

            Gift gift = giftMap.get(giftId);
            Gift out = new Gift();
            BeanUtils.copyProperties(gift, out);
            gifts.add(out);
        }

        //保105
        protect105(luckReq, gifts, pool.getId());

        return gifts;
    }

    /**保105*/
    private void protect105(LuckReq2 luckReq, List<Gift> gifts, Integer poolId) {
        //20奖池  投入100000-101000 rate<1.05
        if (luckReq.getPrice() == 20 && appConfigService.getInt("protect105")==1) {
            HashMap<String, BigDecimal> map = userDailyLuckRecordService.getLuckByType(luckReq.getUserId(), luckReq.getPrice());
            Integer pay = map.get("pay").intValue();
//            pay = 100000;
            if (pay !=null && pay.intValue()>=200000 && pay.intValue()<=200200){
                Integer income = map.get("income").intValue();
                int totalPay = pay + gifts.size() * luckReq.getPrice();
                int totalIncome = income + gifts.stream().mapToInt(gift->gift.getCoin()).sum();
                //抽奖后爆率
                if (!checkRate105(totalPay, totalIncome)) {
                    List<Gift> configGifts = poolGiftConfigService.getGiftsByPoolId(poolId).stream().filter(gift -> gift.getCoin()<6000).collect(Collectors.toList());
                    Collections.reverse(configGifts);
                    for (Gift gift : gifts) {
                        //再次检查整体爆率
                        if (!checkRate105(totalPay, totalIncome)) {
                            //取一个新礼物  替换后  用户超过105 不超过500钻 否则就取小于105最大的
                            //取一个新礼物  替换后  用户超过100 不超过500钻 否则就取小于100最大的
                            for (Gift configGift : configGifts) {
                                int incomeIfReplace = totalIncome-gift.getCoin()+configGift.getCoin();
                                if (checkRate105(totalPay, incomeIfReplace)) {
                                    if (incomeIfReplace < (totalPay*1.0d + 500)) {
                                        totalIncome = incomeIfReplace;
                                        BeanUtils.copyProperties(configGift, gift);
                                        break;
                                    }
                                } else {
                                    totalIncome = incomeIfReplace;
                                    BeanUtils.copyProperties(configGift, gift);
                                    break;
                                }
                            }
                        } else {
                            break;
                        }
                    }

                    //替换后校验  如果爆率大于1.08  异常
                    totalPay = pay + gifts.size() * luckReq.getPrice();
                    totalIncome = income + gifts.stream().mapToInt(gift->gift.getCoin()).sum();
//                    printRate("end", totalPay, totalIncome);
                    if(BigDecimal.valueOf(totalIncome).divide(BigDecimal.valueOf(totalPay), 4, 2).doubleValue() > 1.08) {
                        throw new RRException("错误10002");
                    }
                }
            }
        }

        //最大亏200000  2w
    }

    private void  printRate(String prex, int pay, int income) {
        System.out.println(prex+" pay:"+ pay +"  income:"+income + " r:"+BigDecimal.valueOf(income).divide(BigDecimal.valueOf(pay), 4, 2).doubleValue());
    }
    //是否大于105爆率
    private boolean checkRate105(int pay, int income) {
//        return BigDecimal.valueOf(income).divide(BigDecimal.valueOf(pay), 4, 2).doubleValue() > 1.05;
        return BigDecimal.valueOf(income).divide(BigDecimal.valueOf(pay), 4, 2).doubleValue() > 1.0;
    }

    /**打印抽奖结果*/
    private void tjResult(List<Gift> gifts){
        Map<Integer, Integer> map = new HashMap<>();
        for (Gift gift : gifts) {
            Integer coin = gift.getCoin();
            if (map.containsKey(coin)) {
                map.put(coin, map.get(coin)+1);
            } else {
                map.put(coin, 1);
            }
        }
        System.out.println(JSON.toJSON(map));
    }

    //随机数
    private int doLuck(Map<Integer, Integer> map) {
        Map<Integer, Integer> filterMap = map.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));

        int sum = filterMap.values().stream().mapToInt(Integer::intValue).sum();//数量总和

        if (sum<=0) {
            return 0;
        }
        int i = new Random().nextInt(sum);
        int t = 0;
        for (Map.Entry<Integer, Integer> entry : filterMap.entrySet()) {
            t += entry.getValue();
            if (i<t) {
                map.put(entry.getKey(), entry.getValue()-1);
                return entry.getKey();
            }
        }
        return 0;
    }

    //获取奖池
    public Map<Integer, Integer> getPool(String key, Pool pool){
        Type type = new TypeToken<Map<Integer, Integer>>(){}.getType();
        Map<Integer, Integer> map = (Map<Integer, Integer>) redisConfigService.getJson(key, type);
        //如果奖池空了
        if (map == null|| map.values().stream().mapToInt(Integer::intValue).sum() <=0) {
            map = poolGiftConfigService.getPoolGifts(pool);
        }
        return map;
    }

    /**
     * 获取机器人奖池
     * @param key
     * @param pool
     * @return
     */
    public Map<Integer, Integer> getRobPool(String key, Pool pool){
        Type type = new TypeToken<Map<Integer, Integer>>(){}.getType();
        Map<Integer, Integer> map = (Map<Integer, Integer>) redisConfigService.getJson(key, type);
        //如果奖池,礼物数量为0，空了，重新查询获取奖池数据
        if (map == null|| map.values().stream().mapToInt(Integer::intValue).sum() <=0) {
            map = poolGiftConfigService.getRobPoolGifts(pool);
        }
        return map;
    }

    //跟新奖池
    public void updatePool(String key, Map<Integer, Integer> map) {
        redisConfigService.setJson(key, map);
    }

    //计算最大礼物
    private int getMaxGift(LuckReq2 luckReq, HashMap<String, BigDecimal> winMap, String ip, String device, PoolRoom poolRoom) {

//        int maxWinUser = Integer.parseInt(appConfigService.getVForCache("maxWinUser"));
        int maxGift = poolRoom.getMaxGift();
        //user
        if (winMap.get("userPay") == null || winMap.get("userIncome") == null) {
            HashMap<String, BigDecimal> userMap = userDailyLuckRecordService.getLuckByUser(luckReq.getUserId());
            winMap.put("userIncome", userMap.get("income"));
            winMap.put("userPay", userMap.get("pay"));
        }
        int winUser = (int) (winMap.get("userIncome").doubleValue() * 0.85d - winMap.get("userPay").intValue());
        int maxUser = Math.max(maxGift - winUser, maxGift);

//        int maxWinRoom = Integer.parseInt(appConfigService.getVForCache("maxWinRoom"));
//        int maxWinDevice = Integer.parseInt(appConfigService.getVForCache("maxWinDevice"));
        //room
        if (winMap.get("roomPay")==null || winMap.get("roomIncome")==null) {
            HashMap<String, BigDecimal> roomMap = userDailyLuckRecordService.getLuckByRoomId(luckReq.getRoomId());
            winMap.put("roomIncome",roomMap.get("income"));
            winMap.put("roomPay",roomMap.get("pay"));
        }
        int winRoom = (int) (winMap.get("roomIncome").doubleValue() * 0.85d - winMap.get("roomPay").intValue());
        int maxRoom = Math.max(maxGift-winRoom, maxGift);

        // room Rate
        if (winMap.get("roomRate")==null) {
            if (poolRoom.getRate() != null) {
                winMap.put("roomRate", poolRoom.getRate());
            } else {
                winMap.put("roomRate", BigDecimal.ZERO);
            }
        }
        if (winMap.get("roomRate") != null && winMap.get("roomRate").intValue()!=0 && winMap.get("roomPay").intValue() != 0) {
            if (winMap.get("roomIncome").divide(winMap.get("roomPay"), 4, 2).doubleValue() > winMap.get("roomRate").doubleValue()) {
                maxRoom = maxGift;
            }
        }

        // ip
        if (winMap.get("ipPay")==null || winMap.get("ipIncome")==null) {
            HashMap<String, BigDecimal> ipMap = userDailyLuckRecordService.getLuckByIp(ip);
            winMap.put("ipIncome",ipMap.get("income"));
            winMap.put("ipPay",ipMap.get("pay"));
        }
        int winIp = (int) (winMap.get("ipIncome").doubleValue() * 0.85d - winMap.get("ipPay").intValue());
        int maxIp = Math.max(maxGift-winIp, maxGift);

        // device
        if (winMap.get("devicePay")==null || winMap.get("deviceIncome")==null) {
            HashMap<String, BigDecimal> deviceMap = userDailyLuckRecordService.getLuckByDevice(device);
            winMap.put("deviceIncome",deviceMap.get("income"));
            winMap.put("devicePay",deviceMap.get("pay"));
        }

        int winDevice =  (int) (winMap.get("deviceIncome").doubleValue() * 0.85d - winMap.get("devicePay").intValue());
        int maxDevice = Math.max(maxGift-winDevice, maxGift);

        return Math.min(Math.min(maxDevice, maxIp), Math.min(maxRoom, maxUser));
    }
}
